package com.zw.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zw.dto.AddBasicDataDto;
import com.zw.dto.CloudComputingDto;
import com.zw.entity.BasicData;
import com.zw.mapper.BasicDataMapper;
import com.zw.service.BasicDataService;
import com.zw.utils.*;
import com.zw.utils.encrypt.PaillierAlgorithm;
import com.zw.vo.CloudComputingVO;
import io.jsonwebtoken.lang.Collections;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * (BasicData)表服务实现类
 *
 * @author makejava
 * @since 2025-03-25 23:32:05
 */
@Service("basicDataService")
@Slf4j
public class BasicDataServiceImpl extends ServiceImpl<BasicDataMapper, BasicData> implements BasicDataService {
    @Resource
    private BasicDataMapper basicDataMapper;

    @Value("${aesKey}")
    public String aesKey;

    // 注入密钥（实际应从安全存储获取）
    @Value("${paillier.publicKey.n}")
    private BigInteger publicKeyN;

    @Value("${paillier.publicKey.g}")
    private BigInteger publicKeyG;

    @Value("${paillier.privateKey.lambda}")
    private BigInteger privateKeyLambda;

    @Value("${paillier.privateKey.mu}")
    private BigInteger privateKeyMu;

    @Value("${paillier.privateKey.n}")
    private BigInteger privateKeyN;

    // 初始化密钥
    private PaillierKey.PublicKey publicKey;
    private PaillierKey.PrivateKey privateKey;

    @PostConstruct
    public void init() {
        publicKey = new PaillierKey.PublicKey(publicKeyN, publicKeyG);
        privateKey = new PaillierKey.PrivateKey(privateKeyLambda, privateKeyMu, privateKeyN);
    }

    /**
     * 上传数据
     *
     * @param dto
     * @return
     */
    @Override
    public Boolean addBasicData(AddBasicDataDto dto) throws Exception {
        if (Objects.isNull(dto)) {
            throw new RuntimeException("请求参数错误！");
        }
        //数据校验
        if (dto.getThesisType() == 0) {
            if (Objects.isNull(dto.getThesisDataLanguage()) || Objects.isNull(dto.getThesisDataDate()) || Objects.isNull(dto.getThesisDataNum())) {
                throw new RuntimeException("论文类型数据请求参数错误！");
            }
        }
        if (dto.getPatentType() == 0) {
            if (Objects.isNull(dto.getPatentDate()) || Objects.isNull(dto.getPatentNum())) {
                throw new RuntimeException("专利类型数据请求参数错误！");
            }
        }
        BasicData basicData = CopyUtils.copyObj(dto, BasicData.class);
        //执行对“邮箱”，“作者”，“关键词”，“数据图片url”，“论文时间”，“专利时间”六者的AES加密存储，同时对“数量”进行Paillier加密
        basicData.setEmail(AESUtil.encrypt(basicData.getEmail(), aesKey));
        basicData.setAuthor(AESUtil.encrypt(basicData.getAuthor(), aesKey));
        basicData.setKeyword(AESUtil.encrypt(basicData.getKeyword(), aesKey));
        basicData.setDataUrl(AESUtil.encrypt(String.join(",", dto.getDataUrls()), aesKey));
        basicData.setThesisDataDate(StringUtils.isNotBlank(dto.getThesisDataDate()) ?
                AESUtil.encrypt(LocalDate.parse(dto.getThesisDataDate() + "-01").toString(), aesKey) : null);
        basicData.setPatentDate(StringUtils.isNotBlank(dto.getPatentDate()) ?
                AESUtil.encrypt(LocalDate.parse(dto.getPatentDate() + "-01").toString(), aesKey) : null);
        basicData.setThesisDataNum(Objects.nonNull(dto.getThesisDataNum()) ? PaillierUtil.encrypt(dto.getThesisDataNum(), publicKey) : null);
        basicData.setPatentNum(Objects.nonNull(dto.getPatentNum()) ? PaillierUtil.encrypt(dto.getPatentNum(), publicKey) : null);
        basicData.setCreateBy(SecurityUtils.getEmail());
        basicData.setCreateTime(LocalDate.now());
        int insert = basicDataMapper.insert(basicData);
        if (insert > 0) {
            log.info("数据：{},上传成功！", JSONObject.toJSONString(dto));
            return true;
        }
        return false;
    }

    /**
     * 云端计算
     *
     * @param dto
     * @return
     */
    @Override
    public CloudComputingVO cloudComputing(CloudComputingDto dto) throws Exception {
        if (Objects.isNull(dto)) {
            throw new RuntimeException("请求参数错误！");
        }
        CloudComputingVO vo = new CloudComputingVO();
        List<BasicData> list = basicDataMapper.selectList(new QueryWrapper<BasicData>().lambda()
                .eq(BasicData::getDelFlag, 0));
        if (Collections.isEmpty(list)) {
            return new CloudComputingVO();
        } else {
            List<BasicData> filteredList = new ArrayList<>();
            switch (dto.getFilterField()) {
                case 1:
                    //邮箱筛选
                    filteredList.addAll(list.stream()
                            .filter(data -> {
                                try {
                                    return AESUtil.decrypt(data.getEmail(), aesKey).equals(dto.getFieldValue());
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }) // 定义筛选条件
                            .collect(Collectors.toList())); // 收集结果
                    break;
                case 2:
                    //作者筛选
                    filteredList.addAll(list.stream()
                            .filter(data -> {
                                try {
                                    return AESUtil.decrypt(data.getAuthor(), aesKey).equals(dto.getFieldValue());
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }) // 定义筛选条件
                            .collect(Collectors.toList())); // 收集结果
                    break;
                case 3:
                    //关键词筛选
                    filteredList.addAll(list.stream()
                            .filter(data -> {
                                try {
                                    return AESUtil.decrypt(data.getKeyword(), aesKey).contains(dto.getFieldValue());
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }) // 定义筛选条件
                            .collect(Collectors.toList())); // 收集结果
                    break;
                case 4:
                    //上传时间筛选
                    filteredList.addAll(filterByYearOrMonth(list, dto.getFieldValue(), 1)); // 收集结果
                    break;
                case 5:
                    //文献语言筛选
                    filteredList.addAll(list.stream()
                            .filter(data -> {
                                try {
                                    return Objects.nonNull(data.getThesisDataLanguage()) && data.getThesisDataLanguage().toString().equals(dto.getFieldValue());
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }) // 定义筛选条件
                            .collect(Collectors.toList())); // 收集结果
                    break;
                case 6:
                    //论文时间筛选
                    filteredList.addAll(filterByYearOrMonth(list, dto.getFieldValue(), 2)); // 收集结果
                    break;
                case 7:
                    //专利时间筛选
                    filteredList.addAll(filterByYearOrMonth(list, dto.getFieldValue(), 3)); // 收集结果
                    break;
            }
            if (Collections.isEmpty(filteredList)) {
                return new CloudComputingVO();
            }

            //封装响应结果
            //解密获取总和（需要私钥）
            BigInteger thesisDataSumTotal = PaillierUtil.decrypt(PaillierUtil.batchAdd(filteredList.stream()
                    .filter(data -> data.getThesisDataNum() != null)
                    .map(BasicData::getThesisDataNum)
                    .collect(Collectors.toList()), publicKey), privateKey);
            //解密获取总和（需要私钥）
            BigInteger patentSumTotal = PaillierUtil.decrypt(PaillierUtil.batchAdd(filteredList.stream()
                    .filter(data -> data.getPatentNum() != null)
                    .map(BasicData::getPatentNum)
                    .collect(Collectors.toList()), publicKey), privateKey);
            vo.setThesisDataSum(thesisDataSumTotal.toString());
            vo.setPatentSum(patentSumTotal.toString());
            return vo;
        }
    }

    /**
     * 根据年或年月筛选集合（Java 8 实现）
     *
     * @param list      包含 Date createTime 的对象集合
     * @param timeParam 时间参数（格式："2025" 或 "2025-04"）
     * @return 符合条件的对象列表
     */
    public List<BasicData> filterByYearOrMonth(List<BasicData> list, String timeParam, Integer flag) {
        // 解析时间参数（支持年/年月）
        if (timeParam.matches("\\d{4}")) { // 年格式（2025）
            int targetYear = Integer.parseInt(timeParam);
            switch (flag) {
                case 1:
                    //上传时间筛选
                    return list.stream()
                            .filter(obj -> isSameYear(obj.getCreateTime(), targetYear))
                            .collect(Collectors.toList());
                case 2:
                    //论文时间筛选
                    return list.stream()
                            .filter(obj -> {
                                try {
                                    return StringUtils.isNotBlank(obj.getThesisDataDate()) && isSameYear(LocalDate.parse(AESUtil.decrypt(obj.getThesisDataDate(), aesKey)), targetYear);
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            })
                            .collect(Collectors.toList());
                case 3:
                    //专利时间筛选
                    return list.stream()
                            .filter(obj -> {
                                try {
                                    return StringUtils.isNotBlank(obj.getPatentDate()) && isSameYear(LocalDate.parse(AESUtil.decrypt(obj.getPatentDate(), aesKey)), targetYear);
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            })
                            .collect(Collectors.toList());
            }
        } else if (timeParam.matches("\\d{4}-\\d{2}")) { // 年月格式（2025-04）
            YearMonth targetYm = YearMonth.parse(timeParam);
            switch (flag) {
                case 1:
                    //上传时间筛选
                    return list.stream()
                            .filter(obj -> isSameYearMonth(obj.getCreateTime(), targetYm))
                            .collect(Collectors.toList());
                case 2:
                    //论文时间筛选
                    return list.stream()
                            .filter(obj -> {
                                try {
                                    return Objects.nonNull(obj.getThesisDataDate()) && isSameYearMonth(LocalDate.parse(AESUtil.decrypt(obj.getThesisDataDate(), aesKey)), targetYm);
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            })
                            .collect(Collectors.toList());
                case 3:
                    //专利时间筛选
                    return list.stream()
                            .filter(obj -> {
                                try {
                                    return Objects.nonNull(obj.getPatentDate()) && isSameYearMonth(LocalDate.parse(AESUtil.decrypt(obj.getPatentDate(), aesKey)), targetYm);
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            })
                            .collect(Collectors.toList());
            }
        } else {
            throw new IllegalArgumentException("时间参数格式错误，需为'yyyy'或'yyyy-MM'");
        }
        return new ArrayList<>();
    }

    // ====================================== 核心判断逻辑 ======================================

    /**
     * 判断 Date 是否属于指定年份
     */
    private static boolean isSameYear(LocalDate localDate, int year) {
        return localDate.getYear() == year;
    }

    /**
     * 判断 Date 是否属于指定年月
     */
    private static boolean isSameYearMonth(LocalDate localDate, YearMonth yearMonth) {
        return YearMonth.from(localDate).equals(yearMonth);
    }

}
